package cn.bugstack.infrastructure.persistent.repository;

import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity;
import cn.bugstack.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import cn.bugstack.domain.strategy.myModel.vo.SendMsgVo;
import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.infrastructure.persistent.dao.IStrategyAwardDao;
import cn.bugstack.infrastructure.persistent.dao.IStrategyDao;
import cn.bugstack.infrastructure.persistent.dao.IStrategyRuleDao;
import cn.bugstack.infrastructure.persistent.po.Strategy;
import cn.bugstack.infrastructure.persistent.po.StrategyAward;
import cn.bugstack.infrastructure.persistent.po.StrategyRule;
import cn.bugstack.infrastructure.persistent.redis.IRedisService;
import cn.bugstack.types.common.Constants;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @Description
 * @Author Lx
 * @Date 2024/7/29 0:38
 **/
@Repository
public class StrategyRepository implements IStrategyRepository {

    @Resource
    IRedisService iRedisService;

    @Resource
    IStrategyAwardDao iStrategyAwardDao;


    @Resource
    IStrategyDao iStrategyDao;

    @Resource
    IStrategyRuleDao iStrategyRuleDao;

    @Override
    public List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId) {
        //根据策略id拿到策略的奖品


        //1.先尝试从缓存中拿到策略奖品列表
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_KEY + strategyId;
        List<StrategyAwardEntity> strategyAwardEntities = iRedisService.getValue(cacheKey);

        //2.缓存中拿不到就从数据库中拿，并且最后更新回缓存中

        if(strategyAwardEntities == null||strategyAwardEntities.size()==0){

            //2.1.拿到策略奖品列表
            List<StrategyAward> strategyAwards = iStrategyAwardDao.queryStrategyAwardListByStrategyId(strategyId);
            //2.2开始装配返回结果
            strategyAwardEntities = new ArrayList<>(strategyAwards.size());
            for (StrategyAward strategyAward : strategyAwards) {
                StrategyAwardEntity strategyAwardEntity = StrategyAwardEntity.builder()
                        .strategyId(strategyAward.getStrategyId())
                        .awardId(strategyAward.getAwardId())
                        .awardCount(strategyAward.getAwardCount())
                        .awardCountSurplus(strategyAward.getAwardCountSurplus())
                        .awardRate(strategyAward.getAwardRate())
                        .build();
                strategyAwardEntities.add(strategyAwardEntity);
            }
            //2.3更新缓存
            iRedisService.setValue(cacheKey, strategyAwardEntities);
        }
        return strategyAwardEntities;
    }

    //存概率范围、
    @Override
    public void storeStrategyAwardSearchRateTable(Long strategyId, int rateRange, Map<Integer, Integer> shuffleStrategyAwardSearchRateMap) {
        //1.存到redis中去(把奖品的概率的范围存到redis)
        String cacheKey = Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId;
        iRedisService.setValue(cacheKey,rateRange);//把对应的策略的奖品的概率存到redis中去.每个策略对应不同的奖品、不同的奖品概率、不同的规则
        //2.存储概率查询表(更新奖品概率表到redis)
        //redissonClient.getMap返回的是RMap，是redis中数据map的一个代理，我们在外面修改map，会直接影响到redis中的数据库，所以就不用修改后再set回redis中了
        Map<Integer, Integer> cacheTable = iRedisService.getMap(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId);
        cacheTable.putAll(shuffleStrategyAwardSearchRateMap);//把奖品概率信息表给更新到redis中去
    }

    @Override
    public int getStrategyAwardAssemble(Long strategyId, int RandomValue) {
        //1.根据RandomValue去map中拿奖品
        Map <Integer, Integer> map = iRedisService.getMap(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId);
        Integer AwardId = map.get(RandomValue);
        //也可以两个接口合成一个,getFromMap
        //return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId, rateKey);

        return AwardId;
    }

    @Override
    public int getRateRange(Long strategyId) {
        //1.先去缓存中找，如果缓存中没有，就再到数据库中去找
        String cacheKey = Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId;
        int RateRange = iRedisService.getValue(cacheKey);
        return RateRange;
    }
    @Override
    public int getRateRange(String strategyId) {
        //1.先去缓存中找，如果缓存中没有，就再到数据库中去找
        String cacheKey = Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId;
        int RateRange = iRedisService.getValue(cacheKey);
        return RateRange;
    }

    @Override
    public String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel) {//比之前那个根据策略ID和规则名称抽的多传了一个奖品ID的字段
        StrategyRule strategyRule = new StrategyRule();
        strategyRule.setStrategyId(strategyId);
        strategyRule.setAwardId(awardId);
        strategyRule.setRuleModel(ruleModel);
        return iStrategyRuleDao.queryStrategyRuleValue(strategyRule);
    }

    @Override
    public StrategyAwardRuleModelVO queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId) {
        StrategyAward strategyAward = new StrategyAward();
        strategyAward.setStrategyId(strategyId);
        strategyAward.setAwardId(awardId);
        String ruleModels = iStrategyRuleDao.queryStrategyAwardRuleModels(strategyAward);
        return StrategyAwardRuleModelVO.builder().ruleModels(ruleModels).build();
    }

    @Override
    public String queryStrategyRuleValue(Long strategyId, String ruleModel) {
        return queryStrategyRuleValue(strategyId, null, ruleModel);

    }

    @Override
    public void sendDeductStockMsg(Long strategyId, Integer awardId) {
        String cacheKey = Constants.QueueKey.STRATEGY_Send_Queue_KEY + strategyId + awardId;
        RBlockingQueue<SendMsgVo> blockingQueue = iRedisService.getBlockingQueue(cacheKey);
        RDelayedQueue<SendMsgVo> delayedQueue = iRedisService.getDelayedQueue(blockingQueue);
        //1.构造消息体(扣减库存，库存表用策略id，awardId作为索引
        SendMsgVo sendMsgVo = SendMsgVo.builder()
                .strategyId(String.valueOf(strategyId))
                .awardId(String.valueOf(awardId))
                .build();
        //2.发送
        delayedQueue.offer(sendMsgVo,500, TimeUnit.MILLISECONDS);
    }

    @Override
    public void DecrStockFromCache() {

    }


    @Override
    public StrategyEntity queryStrategyEntityByStrategyId(Long strategyId) {
        //1.先从缓存中拿策略业务实体对象
        String cacheKey =Constants.RedisKey.STRATEGY_KEY + strategyId;
        StrategyEntity strategyEntity = iRedisService.getValue(cacheKey);
        if(strategyEntity!=null) return strategyEntity;

        //2.从数据库中拿
        //2.1.从库中根据策略ID拿到策略数据库对象实体
        Strategy strategy = iStrategyDao.queryStrategyListByStrategyId(strategyId);
        //2.2.封装进业务实体
        strategyEntity = new StrategyEntity().builder()
                .strategyId(strategy.getStrategyId())
                .strategyDesc(strategy.getStrategyDesc())
                .ruleModels(strategy.getRuleModels())
                .build();

        //3.设置进缓存中
        iRedisService.setValue(cacheKey, strategyEntity);


        //4.返回
        return strategyEntity;
    }

    @Override
    public StrategyRuleEntity queryStrategyRuleByStrategyIdAndRuleName(Long strategyId, String ruleModel) {
        //1.从数据库中去拿出规则数据库对象实体，里面有详情列表(不是用List存的，而是用String存的，我们从中解析出来即可)
        //1.1.封装查询参数
        StrategyRule strategyRule = new StrategyRule();
        strategyRule.setStrategyId(strategyId);
        strategyRule.setRuleModel(ruleModel);
        StrategyRule strategyRules = iStrategyRuleDao.queryStrategyRule(strategyRule);
        //2.封装策略规则业务实体
        StrategyRuleEntity strategyRuleEntity = new StrategyRuleEntity().builder()
                .strategyId(strategyRules.getStrategyId())
                .awardId(strategyRules.getAwardId())
                .ruleType(strategyRules.getRuleType())
                .ruleModel(strategyRules.getRuleModel())
                .ruleValue(strategyRules.getRuleValue())
                .ruleDesc(strategyRules.getRuleDesc())
                .build();

        //3.返回
        return strategyRuleEntity;
    }
}
